package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.api.content.model.dot.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.controller.CourseAuditController;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {


    @Override
    public PageVO queryCourseBaseList(PageRequestParams params, QueryCourseModel model, Long id) {
        //判断关键数据--分页数据的合法性 非法数据
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        //构建分页对象
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        //构建查询条件
        //课程名称  模糊匹配 like  课程审核状态 精确匹配eq
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        //判断课程名称是否为空
        String name = model.getCourseName();

        //工具类 java判空工具类 判断是否为空
        if (StringUtils.isNotBlank(name)) {
            wrapper.like(CourseBase::getName, name);
        }
        String status = model.getAuditStatus();
        if (StringUtils.isNotBlank(status)) {
            wrapper.eq(CourseBase::getAuditStatus, status);
        }
        if (!(ObjectUtils.nullSafeEquals(id,
                CourseAuditController.OPERATION_FLAG))) {
            wrapper.eq(CourseBase::getCompanyId, id);
        }

        Page<CourseBase> page1 = this.page(page, wrapper);

        //查询数据到list集合中
        List<CourseBase> records = page1.getRecords();
        List<CourseBaseDTO> list = Collections.emptyList();
        //判断是否为空
        if (!CollectionUtils.isEmpty(records)) {
            list = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }
        //总页数
                                        long total = page1.getTotal();
        //配置返回结果数据封装
        PageVO<CourseBase> vo = new PageVO(list, total, params.getPageNo(), params.getPageSize());
        return vo;

    }


    /*
     * 业务分析
     *  1 增删改要开启事务
     *  2 判断关键数据  有这个数据才可以操作 一般都是前端传入
     *  3 判断业务数据(添加没有业务数据)    后端查询 系统中存在的数据
     *  4 判断数据是否要添加默认值
     *  5 将dto转为po  mp只能对pojo类进行操作
     *  6 保存数据 判断结果是否成功
     *  7  结果成功再将数据转为dto并返回
     * */

    @Autowired
    private CourseMarketService courseMarketService;

    @Override
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {

        //该代码已经通过ctrl+alt+M 封装为一个方法verifyCourseMsg;
        verifyCourseMsg(dto);

        // 4 判断数据是否要添加默认值  审核状态需要添加
        dto.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        //5 将dto转为po数据 因为mp只支持对pojo类操作
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);

        //  6 保存数据 判断结果是否成功
        boolean save = this.save(courseBase);
        if (!save) {
            throw new RuntimeException();
        }
        //  6.1 还要保存课程营销信息
        CourseMarket market = new CourseMarket();
        market.setCourseId(courseBase.getId()); //新添加的数据 id值是新的
        market.setCharge(dto.getCharge());
        market.setPrice(dto.getPrice().floatValue());
        //保存CourseMarket  但是上面已经用了save了 所以：要开头引入CourseMarketService层
        boolean save1 = courseMarketService.save(market);
        if (!save1) {
            throw new RuntimeException("课程营销数据保存失败");
        }
        //该代码已经通过ctrl+alt+M 封装为一个方法getLastCourseBaseDTO;
        Long id = courseBase.getId();
        CourseBaseDTO dto1 = getLastCourseBaseDTO(dto, id);

        return dto1;
    }

    private CourseBaseDTO getLastCourseBaseDTO(CourseBaseDTO dto, Long id) {
        //将数据库的最新添加数据转为dto
        CourseBase base = this.getById(id);
        CourseBaseDTO dto1 = CourseBaseConvert.INSTANCE.entity2dto(base);
        dto1.setCharge(dto.getCharge());
        dto1.setPrice(dto.getPrice());
        return dto1;
    }

    private void verifyCourseMsg(CourseBaseDTO dto) {
        //2.判断关键数据
        // 课程基础信息
        // companyId name mt st grade teachmode users pic（后期来判断）
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 业务异常：程序员在做业务判断时，数据有问题。
            // 异常：
            // 1.终止程序
            // 2.传递错误信息
            // 3.使用运行时异常来抛出
            // 运行时异常不需在编译期间处理
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }
        if (StringUtil.isBlank(dto.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        if (StringUtil.isBlank(dto.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }
        if (StringUtil.isBlank(dto.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }
        if (StringUtil.isBlank(dto.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }
        if (StringUtil.isBlank(dto.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }
        if (StringUtil.isBlank(dto.getUsers())) {

            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        if (StringUtil.isBlank(dto.getCharge())) {
            ExceptionCast.cast(ContentErrorCode.E_120104);
        }
    }


    @Override
    public CourseBaseDTO getCourseBase(Long courseBaseId, Long companyId) {
        //判断数据的合法性
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("传入参数有误，请重新传入");
        }
        //判断业务数据的合法性 并返回业务数据
        // 该代码已经通过ctrl+alt+M 封装为一个方法getCourseBaseByBaseId;
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        //课程营销数据
        //该代码已经通过ctrl+alt+M 封装为一个方法getCourseMarketByCourseId;
        CourseMarket courseMarket = getCourseMarketByCourseId(courseBaseId);

        //返回给前端dto数据  dot中还有营销数据没填写
        CourseBaseDTO dto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        // dot中还有营销数据
        dto.setPrice(new BigDecimal(courseMarket.getPrice().toString()));
        dto.setCharge(courseMarket.getCharge());
        //返回结果
        return dto;
    }


    public CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        //判断业务数据是否存在
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getCompanyId, companyId)
                .eq(CourseBase::getId, courseBaseId);
        CourseBase one = this.getOne(queryWrapper);
        //判断是否有数据
        if (ObjectUtils.isEmpty(one)) {
            throw new RuntimeException("抱歉 您所查询的数据不存在");
        }
        //这里还有一个数据要判断下 就是startus(是否删除) 通过枚举类
        Integer oneStatus = one.getStatus();
        if (CommonEnum.USING_FLAG.getCodeInt().equals(oneStatus)) {
            throw new RuntimeException("课程信息已经被删除");
        }
        return one;
    }


    private CourseMarket getCourseMarketByCourseId(Long courseBaseId) {
        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseMarket::getId, courseBaseId);
        //获取当前coursemarket的数据
        CourseMarket courseMarketServiceOne = courseMarketService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(courseMarketServiceOne)) {
            throw new RuntimeException("课程营销数据不存在");
        }
        return courseMarketServiceOne;
    }


    // 1 判断关键数据
    // 2 判断业务数据
    // 3 修改内容数据
    //4  返回数据并封装为DTO

    @Override
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO voentity) {
        //1判断关键数据
        //该代码已经通过ctrl+alt+M 封装为一个方法verifyCourseMsg;
        verifyCourseMsg(voentity);

        //2 判断业务数据   修改数据时 依据的是课程的id值
        if (ObjectUtils.isEmpty(voentity.getCourseBaseId())) {
            throw new RuntimeException("修改课程ID不能为空");
        }

        //2.1 判断课程基础信息
        //2.1 课程营销数据 是否存在 是否是同一教学机构 是否是删除状态
        // 该代码已经通过ctrl+alt+M 封装为一个方法getCourseBaseByBaseId;
        CourseBase courseBaseByBaseId = getCourseBaseByBaseId(voentity.getCourseBaseId(), voentity.getCompanyId());

        //2.3 课程审核状态判断：未提交 审核不通过 等
        // AUDIT_PASTED_STATUS审核通过
        //AUDIT_COMMIT_STATUS 已提交
        //AUDIT_PUBLISHED_STATUS课程已发布
        String auditStatus = courseBaseByBaseId.getAuditStatus();
        if (
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                        CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                        CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("审核状态不对");
        }


        // 该代码已经通过ctrl+alt+M 封装为一个方法getCourseMarketByCourseId;
        getCourseMarketByCourseId(voentity.getCourseBaseId());

        //3 修改内容表 课程信息表 营销数据表  里面的有些数据不能被修改 比如教学机构ID 审核状态等

        CourseBase popo = CourseBaseConvert.INSTANCE.dto2entity(voentity);
        //防止前端乱修改后台数据 设置为nulll MP的nacos配置非空判断 默认不修改。
        popo.setCompanyId(null);
        popo.setAuditStatus(null);
        popo.setStatus(null);

        boolean b = this.updateById(popo);
        //4 判断修改后的结果
        if (!b) {
            throw new RuntimeException("课程修改失败");
        }

        //修改课程营销表
        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseMarket::getCharge, voentity.getCharge());

        //是否为收费模式
        String charge = voentity.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            //判断价格是不是为空
            BigDecimal price = voentity.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                throw new RuntimeException("收费课程价格不能为空");
            }
            updateWrapper.set(CourseMarket::getPrice, price.floatValue());
        }
        updateWrapper.eq(CourseMarket::getCourseId, voentity.getCourseBaseId());

        boolean b1 = courseMarketService.update(updateWrapper);
        if (!b1) {
            throw new RuntimeException("修改课程营销数据失败");
        }
        CourseBaseDTO dto = getLastCourseBaseDTO(voentity, voentity.getCourseBaseId());
        //5 返回前端修改后的数据 封装为dto
        return dto;
    }


    @Override
    @Transactional
    public void deleteCourse(Long courseBaseId, Long companyId) {
        // 1 判断必要数据
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //1.2  判断业务数据   是不是同一家机构的
        CourseBase courseBase = this.getById(courseBaseId);
        if (!ObjectUtils.nullSafeEquals(courseBase.getCompanyId(), companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100108);
        }

        //1.3 判断审核状态
        String s = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(s) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(s) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(s)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        // 2 .修改课程信息状态值
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBase.getId());
        boolean b = this.update(updateWrapper);
        if (!b) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }


    /*
     * 业务分析：
     *   1.判断关键数据
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断审核状态
     *   3.修改课程审核状态
     *       已提交
     * */
    @Override
    public void commitCourseBase(Long courseBaseId, Long companyId) {
        //关键数据判断
        if (ObjectUtils.isEmpty(companyId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        // 2.判断业务数据
        //     课程基础信息
        //         判断是否存在
        //         判断是否是同一家教学机构
        //         判断是否删除
        //         判断审核状态
        getCourseByLogic(companyId, courseBaseId);

        // 3.修改课程审核状态
        //     已提交
        //  createDate  changeDate 使用MP自动填充来完成
        //  UpdateWrapper 会将MP的自动填充功能失效
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode())
                .set(CourseBase::getChangeDate, LocalDateTime.now())
                .eq(CourseBase::getId, courseBaseId);
        boolean update = this.update(updateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }


    }


    //判断数据是否正常
    private void getCourseByLogic(Long companyId, Long courseBaseId) {
        //引用之前的判断 查询是否有这个课程信息
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        String status = courseBase.getAuditStatus();
        if (
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(status) ||
                        CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(status) ||
                        CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(status)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }

    }


    /*
     * 业务分析：
     *   1.判断关键数据
     *       auditMind  auditStatus  courseid
     *
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否删除
     *           判断审核状态
     *               必须为：已提交
     *       审核状态
     *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
     *   3.修改课程审核信息
     *       auditMind  auditStatus  auditNum（每次+1）
     * */
    @Override
    public void approve(CourseBaseDTO dto) {
        if (
                StringUtils.isBlank(dto.getAuditStatus()) ||
                        StringUtils.isBlank(dto.getAuditMind()) ||
                        ObjectUtils.isEmpty(dto.getCourseBaseId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //  2.判断业务数据
        //      课程基础信息
        //          判断是否存在
        //          判断是否删除
        //          判断审核状态
        //              必须为：已提交
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt())
                .eq(CourseBase::getId, dto.getCourseBaseId())
                .eq(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        int count = this.count(queryWrapper);
        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }

        //      审核状态
        //          运营平台只能给课程审核状态赋值：审核通过、审核未通过
        String auditStatus = dto.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus)) {

        }


        //  3.修改课程审核信息
        //      auditMind  auditStatus  auditNum（每次+1）
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, dto.getAuditStatus()); //改变审核状态
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());//改变审核意见
        // 使用redis来实现 redis可以实现自增的
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now()); //修改时间
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId()); //根据课程信息
        boolean update = this.update(updateWrapper);
        if (update) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }
}
